package com.gyx.lottery.service.impl;
import cn.hutool.crypto.digest.DigestUtil;
import com.gyx.lottery.common.errorcode.ServiceErrorCodeConstants;
import com.gyx.lottery.common.exception.ServiceException;
import com.gyx.lottery.common.utils.JWTUtil;
import com.gyx.lottery.common.utils.RedisUtil;
import com.gyx.lottery.common.utils.RegexUtil;
import com.gyx.lottery.controller.param.ShortMessageLoginParam;
import com.gyx.lottery.controller.param.UserLoginParam;
import com.gyx.lottery.controller.param.UserPasswordLoginParam;
import com.gyx.lottery.controller.param.UserRegisterParam;
import com.gyx.lottery.dao.dataobject.Encrypt;
import com.gyx.lottery.dao.dataobject.UserDO;
import com.gyx.lottery.dao.mapper.UserMapper;
import com.gyx.lottery.service.UserService;
import com.gyx.lottery.service.VerificationCodeService;
import com.gyx.lottery.service.dto.UserDTO;
import com.gyx.lottery.service.dto.UserLoginDTO;
import com.gyx.lottery.service.dto.UserRegisterDTO;
import com.gyx.lottery.service.enums.UserIdentifyEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 实现用户注册业务逻辑
 */
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserMapper userMapper;
    @Autowired
    VerificationCodeService verificationCodeService;
    @Autowired
    RedisUtil redisUtil;
    Logger logger= LoggerFactory.getLogger(UserServiceImpl.class);
    @Override
    public UserRegisterDTO register(UserRegisterParam param) {
        //1.进行参数合法校验
        checkRegisterInfo(param);

        //2.进行数据加密
        UserDO userDO=new UserDO();
        userDO.setUserName(param.getName());
        userDO.setEmail(param.getMail());
        userDO.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        userDO.setIdentity(param.getIdentity());
       if(StringUtils.hasText(param.getPassword())){
           userDO.setPassword(DigestUtil.sha256Hex(param.getPassword()));//进行加密操作
       }
        //3.保存信息
        userMapper.insert(userDO);


        //4.构造返回结果
        UserRegisterDTO userRegisterDTO=new UserRegisterDTO();
        userRegisterDTO.setUserId(userDO.getId());
        return userRegisterDTO;
    }

    @Override
    public UserLoginDTO login(UserLoginParam param) {

        UserLoginDTO userLoginDTO;

        //判断是什么类型
        if(param instanceof  UserPasswordLoginParam loginParam){
            userLoginDTO=userLoginByPassword(loginParam);
        }//使用密码登录
        else if(param instanceof ShortMessageLoginParam loginParam){
            userLoginDTO=userLoginByShortMessage(loginParam);
        }  //使用短信验证码登录
        else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_STYLE_NOT_EXIST);
        } //其他，抛异常
        return userLoginDTO;
    }

    @Override
    public List<UserDTO> findUserList(UserIdentifyEnum identity) {
        String userIdentity=identity==null?null:identity.name();
        List<UserDO> userDOList=userMapper.selectUserByIdentity(userIdentity);
        List<UserDTO>userDTOList=
                userDOList.stream()
                .map(userDO->{
                    UserDTO userDTO=new UserDTO();
                    userDTO.setUserId(userDO.getId());
                    userDTO.setUserName(userDO.getUserName());
                    userDTO.setEmail(userDO.getEmail());
                    userDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    userDTO.setIdentity(UserIdentifyEnum.forName(userDO.getIdentity()));
                    return userDTO;
                }).collect(Collectors.toList());

        return userDTOList;
    }

    private UserLoginDTO userLoginByShortMessage(ShortMessageLoginParam loginParam) {
        //校验手机号格式
        if(!RegexUtil.checkMobile(loginParam.getLoginMobile())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ILLEGAL);
        }
        //进行用户信息获取
        UserDO userDO=userMapper.selectByPhone(new Encrypt
                (loginParam.getLoginMobile())
        );
        if(null == userDO){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_EMPTY);
        }else if(StringUtils.hasLength(loginParam.getMandatoryIdentity())&&
        !userDO.getIdentity().equalsIgnoreCase(loginParam.getMandatoryIdentity()))
        {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        else if(loginParam.getVerificationCode()!=null&&
                !loginParam.getVerificationCode()
                        .equals(verificationCodeService.
                                getVerificationCode(loginParam.getLoginMobile()))){
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATIONCODE_ERROR);
        }
        //校验完毕之后，进行上级信息返回
        UserLoginDTO userLoginDTO=new UserLoginDTO();
        Map<String,Object>claims=new HashMap<>();
        claims.put("id",userDO.getId());
        claims.put("identity",userDO.getIdentity());
        String token = JWTUtil.getJWT(claims);
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentiy(UserIdentifyEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }

    private UserLoginDTO userLoginByPassword(UserPasswordLoginParam loginParam) {
        //校验哪种登陆方式
        UserDO userDO = null;
        if(RegexUtil.checkMail(loginParam.getLoginName())){
             userDO = userMapper.selectByMail(loginParam.getLoginName());
        }
        else if(RegexUtil.checkMobile(loginParam.getLoginName())){
             userDO = userMapper.selectByPhone(new Encrypt(loginParam.getLoginName()));
        }
        else{
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIST);
        }
        //校验身份信息是否正确
        if(null==userDO){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_EMPTY);
        }
        else if(StringUtils.hasText(loginParam.getMandatoryIdentity())&&
                !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity()))
        {
           throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }//1.验证身份标识
        else if(!DigestUtil.sha256Hex(loginParam.getPassword()).equals(userDO.getPassword()))
        {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        } //2.校验密码是否在正确
        //构建返回信息jwt

        Map<String,Object>claims=new HashMap<>();
        claims.put("id", userDO.getId());
        claims.put("identity",userDO.getIdentity());
        String token= JWTUtil.getJWT(claims);
        UserLoginDTO userLoginDTO=new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentiy(UserIdentifyEnum.forName(userDO.getIdentity()));
        return  userLoginDTO;
        //进行service层信息返回
    }


    private void checkRegisterInfo(UserRegisterParam param) {
        //1.校验参数是否为空
        if(null==param){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_PARAM_IS_EMPTY);
        }
        //2.校验邮箱合法性
        if(!RegexUtil.checkMail(param.getMail()))
        {
            throw new ServiceException(ServiceErrorCodeConstants.EMAIL_ILLEGAL);
        }
        //3.校验电话号码合法性
        if(!RegexUtil.checkMobile(param.getPhoneNumber()))
        {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ILLEGAL);
        }
        //4.校验身份标识合法性
       if(null==UserIdentifyEnum.forName(param.getIdentity())){
           throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
       }
        //5.校验密码合法性
        //(1)校验密码是否必填
        if((param.getIdentity().equalsIgnoreCase(UserIdentifyEnum.ADMIN.name())
        &&!StringUtils.hasText(param.getPassword()))){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_EMPITY);
        }
        //(2)校验密码合法性(至少6位)
        if(StringUtils.hasText(param.getPassword())&&!RegexUtil.checkPassword(param.getPassword()))
        {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //6.校验邮箱是否已经被使用
        if(checkMainUsed(param.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_MAIL_USED);
        }
        //7.校验手机号是否已经被使用
        if(checkPhoneNumberUsed(param.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);
        }
    }

    /**
     * 校验电话号码是否被使用
     * @param phoneNumber
     * @return
     */
    private boolean checkPhoneNumberUsed(String phoneNumber) {
        return userMapper.countByPhone(new Encrypt(phoneNumber))>0;
    }

    /**
     * 校验邮箱是否已经被使用
     * @param mail
     * @return
     */

    private boolean checkMainUsed(String mail) {
        return userMapper.countByMail(mail)>0;
    }
}
